#include "finger_app.h"

#if (_SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_) && (_SAFETY_VERIFYFUNCTION_ENABLE_)

static FingerBitStatus_t FingerBitStatus = {0};

uint8_t FingerGetTheNumberOfRegisteredUsers(void)
{
  return FingerBitStatus.HardwareAttribute.NumberOfUser;
}

void FingerGetDeviceSerialNumber(char *pSerialNumberOut)
{
  if (pSerialNumberOut != NULL)
  {
    strcpy(pSerialNumberOut, FingerBitStatus.HardwareAttribute.SerialNumber);
  }
}

void FingerGetApplicationVersion(char *pVersionOut)
{
  if (pVersionOut != NULL)
  {
    strcpy(pVersionOut, FingerBitStatus.HardwareAttribute.ApplicationVersion);
  }
}

bool FingerValidateMessage(const void *pMessageIn, uint8_t *pDataOut, uint16_t *pSizeOut, uint8_t *pResultOut)
{
  FingerRxProtocolFormat_t *pRxProtocolFormat = (FingerRxProtocolFormat_t *)pMessageIn;

  if (pRxProtocolFormat != NULL)
  {
    uint8_t FrameHeader[FINGER_FRAME_HEADE_BIT_LENGTH] = {0xF1, 0x1F, 0xE2, 0x2E, 0xB6, 0x6B, 0xA8, 0x8A};

    if (memcmp(pRxProtocolFormat->FrameHead, FrameHeader, FINGER_FRAME_HEADE_BIT_LENGTH) == 0)
    {
      uint8_t CrcValue = FingerCalculateCrcValue(pRxProtocolFormat->FrameHead, (FINGER_FRAME_HEADE_BIT_LENGTH + FINGER_APPLICATION_DATA_SIZE_BIT_LENGTH));
      if (CrcValue == pRxProtocolFormat->FramHeadeCrc)
      {
        uint16_t MessageSize = (pRxProtocolFormat->DataSize[1] | (pRxProtocolFormat->DataSize[0] << 8));

        if ((MessageSize >= FINGER_APPLICATION_FIXED_PARAMETER_LENGTH_RX) && (MessageSize <= FINGER_RX_APPLICATION_DATA_LENGTH(FINGER_APPLICATION_MAX_DATA_BIT_LENGTH)))
        {
          CrcValue = FingerCalculateCrcValue(pRxProtocolFormat->Password, MessageSize - 1);
          if (CrcValue == pRxProtocolFormat->Data[FINGER_RX_PROTOCOL_DATA_LENGTH(MessageSize)])
          {
            uint8_t Password[FINGER_PROTOCOL_PASSWORD_BIT_LENGTH] = {0x00, 0x00, 0x00, 0x00};

            if (memcmp(pRxProtocolFormat->Password, Password, FINGER_PROTOCOL_PASSWORD_BIT_LENGTH) == 0)
            {
              if (pRxProtocolFormat->MasterCommand == FingerBitStatus.EventStatus.MessageId)
              {
                if (pRxProtocolFormat->SubCommand == FingerBitStatus.EventStatus.CommandToSend)
                {
                  if (pResultOut != NULL)
                  {
                    *pResultOut = pRxProtocolFormat->AckCode[3];
                  }

                  if (pSizeOut != NULL)
                  {
                    *pSizeOut = FINGER_RX_PROTOCOL_DATA_LENGTH(MessageSize);
                  }

                  if (pDataOut != NULL)
                  {
                    memcpy(pDataOut, pRxProtocolFormat->Data, FINGER_RX_PROTOCOL_DATA_LENGTH(MessageSize));
                  }

                  return true;
                }
              }
            }
          }
        }
      }
    }
  }

  return false;
}

bool FingerBuildSelfTestMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_TRUE_OFF_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_OFF, FINGER_LED_HINT_NONE, 0, 0, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_EXECUTE_FACTORY_RESET:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_CLEARANCE_SYNCHRONOUS;

      BuildMessageResults = FingerBuildFeatureClearanceSynchronousMessage(FINGER_DELETE_ALL_USER, NULL, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME * 10;
    }
    break;

    case FINGER_GET_SERIAL_NUMBER:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_READ_DEVICE_ENCODING;

      BuildMessageResults = FingerBuildReadDeviceEncodingMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_APPLICATION_VERSION:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_FIRMWARE_VERSION;

      BuildMessageResults = FingerBuildGetFirmwareVersionMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_TEMPLATE_QUANTITY;

      BuildMessageResults = FingerBuildGetTemplateQuantityMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildFactorySettingMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_TRUE_OFF_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_OFF, FINGER_LED_HINT_NONE, 0, 0, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_EXECUTE_FACTORY_RESET:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_CLEARANCE_SYNCHRONOUS;

      BuildMessageResults = FingerBuildFeatureClearanceSynchronousMessage(FINGER_DELETE_ALL_USER, NULL, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME * 100;
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_TEMPLATE_QUANTITY;

      BuildMessageResults = FingerBuildGetTemplateQuantityMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildGetEigenvalueFileMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_GET_IMAGE_INFORMATION:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_INFORMATION_UPLOAD;

      BuildMessageResults = FingerBuildFeatureInformationUploadMessage(FingerBitStatus.EventStatus.TempUserId, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_UPLOAD_IMAGE_DATA:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_DATA_UPLOAD;

      BuildMessageResults = FingerBuildFeatureDataUploadMessage(FingerBitStatus.FileOperation.RequestFileSize, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildForcedToGotoSleepMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_TRUE_OFF_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_OFF, FINGER_LED_HINT_NONE, 0, 0, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_ENROLL_CANCEL:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_CANCEL_REGISTRATION;

      BuildMessageResults = FingerBuildCancelTheCurrentActionMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildLocalRegisterUserMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_TRUE_ON_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_PWN, FINGER_LED_HINT_GREEN, 100, 0, 1, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_WHETHER_THE_FINGER_PRESSED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_QUERY_FINGER_ONLINE_STATUS;

      BuildMessageResults = FingerBuildQueryFingerOnlineStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_USER_INTERACTIVE_REGISTRATION:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_AUTO_REGISTRATION;

      BuildMessageResults = FingerBuildAutomaticRegistrationMessage(true, FINGER_NUMBER_OF_FINGERPRINTING, FINGER_VIRTUAL_USER_CODE, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_IDENTIFY_USER_PERMISSIONS:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_MATCHING;

      BuildMessageResults = FingerBuildMatchingMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_TEMPLATE_QUANTITY;

      BuildMessageResults = FingerBuildGetTemplateQuantityMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_TRUE_OFF_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_OFF, FINGER_LED_HINT_NONE, 0, 0, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildUserAuthenticationMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_TRUE_ON_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_PWN, FINGER_LED_HINT_GREEN, 100, 0, 1, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_TRUE_OFF_LED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SET_LED_CONTROL_INFORMATION;

      BuildMessageResults = FingerBuildSetLedControlInformationMessage(FINGER_LED_CTRL_OFF, FINGER_LED_HINT_NONE, 0, 0, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_WHETHER_THE_FINGER_PRESSED:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_QUERY_FINGER_ONLINE_STATUS;

      BuildMessageResults = FingerBuildQueryFingerOnlineStatusMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_IDENTIFY_USER_PERMISSIONS:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_MATCHING_SYNCHRONOUS;

      BuildMessageResults = FingerBuildMatchingSynchronousMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildDeletingSpecificUsersMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_DELETING_USERS:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_CLEARANCE_SYNCHRONOUS;

      BuildMessageResults = FingerBuildFeatureClearanceSynchronousMessage(FINGER_DELETE_ONLY, &FingerBitStatus.DeleteUserInformation.UserId[FingerBitStatus.DeleteUserInformation.NumberOfDelete - 1], 1, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_EXECUTE_FACTORY_RESET:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_CLEARANCE_SYNCHRONOUS;

      BuildMessageResults = FingerBuildFeatureClearanceSynchronousMessage(FINGER_DELETE_ALL_USER, NULL, 0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME * 10;
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_TEMPLATE_QUANTITY;

      BuildMessageResults = FingerBuildGetTemplateQuantityMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

bool FingerBuildRegistrationByEigenvalueMessage(uint8_t *pMessageOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildMessageResults = false;

  if ((pMessageOut != NULL) && (pSizeOut != NULL) && (pResponseTimeOut != NULL))
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_GET_IDLE_USER_CODE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_QUERY_STORAGE_DISTRIBUTION;

      BuildMessageResults = FingerBuildQueryStorageDistributionMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INFORM_IMAGE_ATTRIBUTE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_INFORMATION_DOWNLOAD;

      BuildMessageResults = FingerBuildFeatureInformationDownloadMessage(FingerBitStatus.EventStatus.TempUserId, FingerBitStatus.FileOperation.FileSize, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_TRANSMIT_FILE_PACKET:
    {
      uint8_t FileDataPacket[FINGER_APPLICATION_MAX_DATA_BIT_LENGTH] = {0};

      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_FEATURE_DATA_DOWNLOAD;

      FingerReadFeatureValueFilesForMemory(FingerBitStatus.FileOperation.RequestFileSize, FileDataPacket, FingerBitStatus.FileOperation.TransmitterSize);

      BuildMessageResults = FingerBuildFeatureDataDownloadMessage(FingerBitStatus.FileOperation.RequestFileSize, FileDataPacket, FingerBitStatus.FileOperation.TransmitterSize, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_ENROLL_CANCEL:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_FINGERPRINT;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_CANCEL_REGISTRATION;

      BuildMessageResults = FingerBuildCancelTheCurrentActionMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_GET_TEMPLATE_QUANTITY;

      BuildMessageResults = FingerBuildGetTemplateQuantityMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_SYSTEM;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_SLEEP_MODE;

      BuildMessageResults = FingerBuildSleepModeMessage(FINGER_SLEEP_MODE_0, pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;

    default:
    {
      FingerBitStatus.EventStatus.MessageId = COMMAND_MAINTENANCE;
      FingerBitStatus.EventStatus.CommandToSend = FINGER_HEARTBEAT;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_COMMUNICATION_TEST;

      BuildMessageResults = FingerBuildHeartbeatMessage(pMessageOut, pSizeOut);
      *pResponseTimeOut = FINGER_MESSAGE_SENGING_RATED_TIME;
    }
    break;
    }
  }

  return BuildMessageResults;
}

uint8_t FingerParsingSelfTestMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FINGER_EXECUTE_ERROR;
  uint8_t *pRegistrationMessage = (uint8_t *)pDataIn;

  if (pRegistrationMessage != NULL)
  {
    switch (FingerBitStatus.EventStatus.StepsOfSending)
    {
    case FINGER_COMMUNICATION_TEST:
    {
      ParsingState = FingerParseHeartbeatMessage(pRegistrationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_TRUE_OFF_LED;
      }
    }
    break;

    case FINGER_TRUE_OFF_LED:
    {
      ParsingState = FingerParseFeatureClearanceSynchronousMessage(pRegistrationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = (FingerGetDeviceActivationStatus() == true) ? FINGER_GET_SERIAL_NUMBER : FINGER_EXECUTE_FACTORY_RESET;
      }
    }
    break;

    case FINGER_EXECUTE_FACTORY_RESET:
    {
      ParsingState = FingerParseFeatureClearanceSynchronousMessage(pRegistrationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_SERIAL_NUMBER;
      }
    }
    break;

    case FINGER_GET_SERIAL_NUMBER:
    {
      ParsingState = FingerParseGetModuleIdMessage(pRegistrationMessage, &FingerBitStatus.HardwareAttribute.SerialNumber);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_APPLICATION_VERSION;
      }
    }
    break;

    case FINGER_GET_APPLICATION_VERSION:
    {
      ParsingState = FingerParseGetFirmwareVersionNumberMessage(pRegistrationMessage, &FingerBitStatus.HardwareAttribute.ApplicationVersion);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_NUMBER_OF_TEMPLATE;
      }
    }
    break;

    case FINGER_GET_NUMBER_OF_TEMPLATE:
    {
      ParsingState = FingerParseGetTemplateQuantityMessage(pRegistrationMessage, &FingerBitStatus.HardwareAttribute.NumberOfUser);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
      }
    }
    break;

    case FINGER_INTO_POWER_DOWM:
    {
      ParsingState = FingerParseSetSleepModeMessage(pRegistrationMessage);
      if (ParsingState == true)
      {
        ParsingResults = FINGER_EXECUTE_OVER;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_WAIT_READY;
      }
    }
    break;

    default:
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
    }
    break;
    }
  }

  return ParsingResults;
}

uint8_t FingerParsingDeviceFactorySettingMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FINGER_EXECUTE_ERROR;
  uint8_t *pFactorySettingMessage = (uint8_t *)pDataIn;

  switch (FingerBitStatus.EventStatus.StepsOfSending)
  {
  case FINGER_COMMUNICATION_TEST:
  {
    ParsingState = FingerParseHeartbeatMessage(pFactorySettingMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_TRUE_OFF_LED;
    }
  }
  break;

  case FINGER_TRUE_OFF_LED:
  {
    ParsingState = FingerParseFeatureClearanceSynchronousMessage(pFactorySettingMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_EXECUTE_FACTORY_RESET;
    }
  }
  break;

  case FINGER_EXECUTE_FACTORY_RESET:
  {
    ParsingState = FingerParseFeatureClearanceSynchronousMessage(pFactorySettingMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_NUMBER_OF_TEMPLATE;
    }
  }
  break;

  case FINGER_GET_NUMBER_OF_TEMPLATE:
  {
    ParsingState = FingerParseGetTemplateQuantityMessage(pFactorySettingMessage, &FingerBitStatus.HardwareAttribute.NumberOfUser);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
    }
  }
  break;

  case FINGER_INTO_POWER_DOWM:
  {
    ParsingState = FingerParseSetSleepModeMessage(pFactorySettingMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_OVER;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_WAIT_READY;
    }
  }
  break;

  default:
  {
    ParsingResults = FINGER_EXECUTE_SUCCESS;
    FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
  }
  break;
  }

  return ParsingResults;
}

uint8_t FingerParsingForcedToGotoSleepMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FINGER_EXECUTE_ERROR;
  uint8_t *pForcedToGotoSleepMessage = (uint8_t *)pDataIn;

  switch (FingerBitStatus.EventStatus.StepsOfSending)
  {
  case FINGER_COMMUNICATION_TEST:
  {
    ParsingState = FingerParseHeartbeatMessage(pForcedToGotoSleepMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_TRUE_OFF_LED;
    }
  }
  break;

  case FINGER_TRUE_OFF_LED:
  {
    ParsingState = FingerParseSetLedControlInformationMessage(pForcedToGotoSleepMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_ENROLL_CANCEL;
    }
  }
  break;

  case FINGER_ENROLL_CANCEL:
  {
    ParsingState = FingerParseCancelRegistrationOrMatchingMessage(pForcedToGotoSleepMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
    }
  }
  break;

  case FINGER_INTO_POWER_DOWM:
  {
    ParsingState = FingerParseSetSleepModeMessage(pForcedToGotoSleepMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_OVER;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_WAIT_READY;
    }
  }
  break;

  default:
  {
    ParsingResults = FINGER_EXECUTE_SUCCESS;
    FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
  }
  break;
  }

  return ParsingResults;
}

uint8_t FingerParsingGetEigenvalueFileMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  return FINGER_EXECUTE_ERROR;
}

uint8_t FingerParsingLocalRegisterMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  bool ParsingState = false;
  uint8_t ParsingResults = FINGER_EXECUTE_ERROR;
  uint8_t *pLocalRegisterMessage = (uint8_t *)pDataIn;

  switch (FingerBitStatus.EventStatus.StepsOfSending)
  {
  case FINGER_COMMUNICATION_TEST:
  {
    ParsingState = FingerParseHeartbeatMessage(pLocalRegisterMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_TRUE_ON_LED;
    }
  }
  break;

  case FINGER_TRUE_ON_LED:
  {
    ParsingState = FingerParseSetLedControlInformationMessage(pLocalRegisterMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_WHETHER_THE_FINGER_PRESSED;
    }
  }
  break;

  case FINGER_GET_WHETHER_THE_FINGER_PRESSED:
  {
    ParsingResults = FINGER_EXECUTE_RETRY;

    uint8_t FingerStatus = 0;
    ParsingState = FingerParseQueryFingerOnlineStatusMessage(pLocalRegisterMessage, &FingerStatus);
    if (ParsingState == true)
    {
      if (FingerStatus == true)
      {
        ParsingResults = FINGER_EXECUTE_SUCCESS;
        FingerBitStatus.EventStatus.StepsOfSending = FINGER_USER_INTERACTIVE_REGISTRATION;
      }
    }
  }
  break;

  case FINGER_USER_INTERACTIVE_REGISTRATION:
  {
    uint16_t TemplateId = 0;
    uint8_t RegisterCount = 0, Progress = 0;

    ParsingState = FingerParseAutomaticRegistrationMessage(pLocalRegisterMessage, &RegisterCount, &TemplateId, &Progress);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_WAIT;

      if (ParsingResult == NORMAL_COMPLETION)
      {
        if (Progress == 100)
        {
          ParsingResults = FINGER_EXECUTE_SUCCESS;
          FingerBitStatus.EventStatus.TempUserId = TemplateId;
          FingerBitStatus.EventStatus.StepsOfSending = FINGER_GET_NUMBER_OF_TEMPLATE;
        }
      }
    }
  }
  break;

  case FINGER_GET_NUMBER_OF_TEMPLATE:
  {
    ParsingState = FingerParseGetTemplateQuantityMessage(pLocalRegisterMessage, &FingerBitStatus.HardwareAttribute.NumberOfUser);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_TRUE_OFF_LED;
    }
  }
  break;

  case FINGER_TRUE_OFF_LED:
  {
    ParsingState = FingerParseSetLedControlInformationMessage(pLocalRegisterMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_SUCCESS;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
    }
  }
  break;

  case FINGER_INTO_POWER_DOWM:
  {
    ParsingState = FingerParseSetSleepModeMessage(pLocalRegisterMessage);
    if (ParsingState == true)
    {
      ParsingResults = FINGER_EXECUTE_OVER;
      FingerBitStatus.EventStatus.StepsOfSending = FINGER_WAIT_READY;
    }
  }
  break;

  default:
  {
    ParsingResults = FINGER_EXECUTE_SUCCESS;
    FingerBitStatus.EventStatus.StepsOfSending = FINGER_INTO_POWER_DOWM;
  }
  break;
  }

  return ParsingResults;
}

uint8_t FingerParsingUserAuthenticationMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  return 0;
}

uint8_t FingerParsingDeletingSpecificUsersMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  return 0;
}

uint8_t FingerParsingRegistrationByEigenvalueMessage(const void *pDataIn, uint16_t DataSize, uint8_t ParsingResult)
{
  return 0;
}

uint16_t FingerGetLocalRegisterUserId(void)
{
  return FingerBitStatus.EventStatus.TempUserId;
}

uint16_t FingerGetAuthorizedUserCode(void)
{
  return FingerBitStatus.EventStatus.TempUserId;
}

void FingerFunctionalInitialization(void)
{
  memset(&FingerBitStatus.EventStatus, 0, sizeof(FingerEventStatus_t));
}

void FingerStartForcedToGotoSleep(void)
{
  memset(&FingerBitStatus.EventStatus, 0, sizeof(FingerEventStatus_t));
}

void FingerStartLocalRegisterTasks(uint8_t WaitTime)
{
  memset(&FingerBitStatus.EventStatus, 0, sizeof(FingerEventStatus_t));

  FingerPreparationsBeforeLocalRegister(WaitTime);
}

#endif
